package com.fengyunhe.utils.http;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

public class HttpClients {

    private static PoolingClientConnectionManager cm = new PoolingClientConnectionManager();

    // public final static String AGENT_FIREFOX =
    // "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Comodo_Dragon/17.4.1.0 Chrome/17.0.963.56 Safari/535.11";
    static {
        SSLContext ctx = null;
        try {
            ctx = SSLContext.getInstance("TLS");
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        }
        try {
            ctx.init(new KeyManager[0],
                    new TrustManager[]{new DefaultTrustManager()},
                    new SecureRandom());
        } catch (KeyManagementException e1) {
            e1.printStackTrace();
        }
        SSLSocketFactory sf = new SSLSocketFactory(ctx,
                SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        Scheme https = new Scheme("https", 443, sf);
        cm.getSchemeRegistry().register(https);
    }

    public static DefaultHttpClient instance() {
        DefaultHttpClient client = new DefaultHttpClient(cm);
        client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(3,
                false));
        return client;
    }

    public static void shutdown(HttpClient client) {
        client.getConnectionManager().shutdown();
    }

    public static HttpResponse get(String url) throws ParseException,
            UnsupportedEncodingException, IOException {
        return get(url, null, null, null, null);
    }

    public static HttpResponse get(String url,
                                   List<? extends org.apache.http.NameValuePair> params,
                                   Header[] headers) throws ParseException,
            UnsupportedEncodingException, IOException {
        return get(url, params, null, null, headers);
    }

    public static HttpResponse get(String url,
                                   List<? extends org.apache.http.NameValuePair> params,
                                   String charset, CookieStore cookies, Header[] headers)
            throws ParseException, UnsupportedEncodingException, IOException {
        HttpResponse resp = null;
        DefaultHttpClient client = instance();
        if (params != null) {
            if (charset == null) {
                charset = "UTF-8";
            }
            String str = EntityUtils.toString(new UrlEncodedFormEntity(params,
                    charset));
            System.out.println(str);

            if (url.indexOf("?") > -1) {
                url += "&" + str;
            } else {
                url += "?" + str;
            }
        }
        HttpGet get = new HttpGet(url);
        get.setHeaders(headers);
        // get.setHeader("User-Agent", AGENT_FIREFOX);

        if (cookies != null) {
            client.setCookieStore(cookies);
        }

        resp = client.execute(get);

        return resp;
    }

    public static HttpResponse post(String url,
                                    List<? extends org.apache.http.NameValuePair> params,
                                    Header[] headers) throws ParseException,
            UnsupportedEncodingException, IOException {
        return post(url, params, null, null, headers);
    }

    public static HttpResponse postString(String url, String stringEntity) throws IOException {
        HttpResponse resp = null;
        DefaultHttpClient client = instance();
        HttpPost post = new HttpPost();
        post.setURI(URI.create(url));
        post.setEntity(new StringEntity(
                stringEntity));
        resp = client.execute(post);
        return resp;
    }

    public static HttpResponse post(String url,
                                    List<? extends org.apache.http.NameValuePair> params,
                                    String charset, CookieStore cookies, Header[] headers)
            throws ClientProtocolException, IOException {
        HttpResponse resp = null;
        HttpPost post = new HttpPost(url);
        if (params != null) {
            if (charset == null) {
                charset = "UTF-8";
            }
            post.setEntity(new UrlEncodedFormEntity(params, charset));
        }
        post.setHeaders(headers);
        // post.setHeader("User-Agent", AGENT_FIREFOX);
        DefaultHttpClient client = instance();
        if (cookies != null) {
            client.setCookieStore(cookies);
        }
        resp = client.execute(post);
        return resp;
    }

    public static HttpResponse postMutipart(String url,
                                            Map<String, String> params, String paramCharset,
                                            CookieStore cookies, Header[] headers, Map<String, File> files)
            throws ClientProtocolException, IOException {
        HttpResponse resp = null;
        HttpPost post = new HttpPost(url);
        MultipartEntity reqEntity = new MultipartEntity();
        if (files != null && files.size() > 0) {
            Set<String> keys = files.keySet();
            for (String k : keys) {
                File file = files.get(k);
                if (file != null && file.exists() && file.isFile()) {
                    FileBody fileBody = new FileBody(file);
                    reqEntity.addPart(k, fileBody);
                }
            }
        }

        if (params != null && params.size() > 0) {
            Set<String> keys = params.keySet();
            for (String k : keys) {
                String str = params.get(k);
                try {
                    StringBody strBody = new StringBody(str,
                            Charset.forName(paramCharset == null ? "utf-8"
                                    : paramCharset));
                    reqEntity.addPart(k, strBody);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        post.setEntity(reqEntity);
        post.setHeaders(headers);
        // post.setHeader("User-Agent", AGENT_FIREFOX);

        DefaultHttpClient client = instance();
        if (cookies != null) {
            client.setCookieStore(cookies);
        }
        resp = client.execute(post);
        return resp;
    }

    public static List<NameValuePair> sort(List<NameValuePair> params) {
        if (params != null) {
            Collections.sort(params, new Comparator<NameValuePair>() {
                @Override
                public int compare(NameValuePair o1, NameValuePair o2) {
                    int compared;
                    compared = o1.getName().compareTo(o2.getName());
                    if (0 == compared) {
                        compared = o1.getValue().compareTo(o2.getValue());
                    }
                    return compared;
                }
            });
        }
        return params;
    }

    final static class DefaultTrustManager implements X509TrustManager {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }
    }

    public static void main(String[] args) {
        try {
            HttpResponse response = get("https://mail.qq.com", null, null);
            System.out.println(EntityUtils.toString(response.getEntity()));
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
